import random
import sys
import time

from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By

from honey import honey_lands
from libs import config
from libs.action import WebDriverAction
from libs.cache import Cache
from libs.game import Game
from libs.image import ImageTool
from libs.log import Log
from libs.movement import Movement
from libs.task_helper import TaskHelper
from libs.trade_helper import TradeHelper
from libs.window import AdsWindow

craft_only_items = {
    'Copperite Screw': {
        'craft_name': 'Pile of Copperite Screws',
        'type': 'metalworking',
        'skill_level': 'metal_6',
        'min_qty': 41,
        'wait_seconds': 154 * 60,
        'energy_cost': 152,
        'buy_items': {
            'Copperite Ore': 12,
        }
    },
    'Popberry Pie': {
        'type': 'spec_cooking',
        'skill_level': 'cooking_2',
        'min_qty': 40,
        'wait_seconds': 18 * 60,
        'energy_cost': 12,
        'buy_items': {
            'Popberry Jam': 2,
            'Cooking Mix': 1,
        }
    },
    'Popberry Loaf': {
        'type': 'spec_cooking',
        'skill_level': 'cooking_6',
        'min_qty': 40,
        'wait_seconds': 22 * 60,
        'energy_cost': 14,
        'buy_items': {
            'Popberry Jam': 3,
            'Grainbow Flour': 2,
        }
    },
    'Blue Grumpkin Pie': {
        'type': 'spec_cooking',
        'skill_level': 'cooking_15',
        'min_qty': 40,
        'wait_seconds': 29 * 60,
        'energy_cost': 16,
        'buy_items': {
            'Blue Grumpkin Puree': 3,
            'Cooking Mix': 1,
        }
    },
    'Blue Grumpkin Loaf': {
        'type': 'spec_cooking',
        'skill_level': 'cooking_17',
        'min_qty': 40,
        'wait_seconds': 29 * 60,
        'energy_cost': 16,
        'buy_items': {
            'Blue Grumpkin Puree': 4,
            'Grainbow Flour': 2,
        }
    },
    'Grainbow Tart': {
        'type': 'spec_cooking',
        'skill_level': 'cooking_8',
        'min_qty': 40,
        'wait_seconds': 24 * 60,
        'energy_cost': 15,
        'buy_items': {
            'Popberry Jam': 1,
            'Grainbow Flour': 2,
            'Grainbow': 8,
        }
    },
    'Clover Fruit Pie': {
        'type': 'spec_cooking_v2',
        'skill_level': 'cooking_25',
        'min_qty': 40,
        'wait_seconds': 47 * 60,
        'energy_cost': 23,
        'buy_items': {
            'Clover Fruit Jam': 3,
            'Cooking Mix': 1,
        }
    },
    'Java Pie': {
        'type': 'spec_cooking_v2',
        'skill_level': 'cooking_35',
        'min_qty': 40,
        'wait_seconds': 60 * 60,
        'energy_cost': 25,
        'buy_items': {
            'Java Jam': 2,
            'Cooking Mix': 1,
        }
    },
    'Orange Grumpkin Pie': {
        'type': 'spec_cooking_v2',
        'skill_level': 'cooking_20',
        'min_qty': 40,
        'wait_seconds': 46 * 60,
        'energy_cost': 23,
        'buy_items': {
            'Orange Grumpkin Puree': 3,
            'Cooking Mix': 1,
        }
    },
    'Tato Hash': {
        'type': 'spec_cooking_v2',
        'skill_level': 'cooking_27',
        'min_qty': 70,
        'wait_seconds': 47 * 60,
        'energy_cost': 22,
        'buy_items': {
            'Tato Fruit': 2
        }
    },
    'Tato Scramble': {
        'type': 'spec_cooking_v2',
        'skill_level': 'cooking_30',
        'min_qty': 40,
        'wait_seconds': 60 * 60,
        'energy_cost': 25,
        'make_items': {
            'Tato Hash': 3
        },
        'buy_items': {
            'Popberry': 1,
            'Blue Grumpkin': 1,
            'Orange Grumpkin': 1,
            'Clover': 1,
        }
    },
    "Muckchuck Pie": {
        'type': 'land_cooking',
        'skill_level': 'cooking_40',
        'min_qty': 40,
        'wait_seconds': 61 * 60,
        'energy_cost': 36,
        'buy_items': {
            'Muckchuck Jam': 2,
            'Cooking Mix': 1,
        }
    },
    "Napricot Pie": {
        'type': 'land_cooking',
        'skill_level': 'cooking_45',
        'min_qty': 40,
        'wait_seconds': 61*60,
        'energy_cost': 36,
        'buy_items': {
            'Napricot Jam': 2,
            'Cooking Mix': 1,
        }
    },
    "Slice of Slothmato Pizza": {
        'craft_name': 'Slothmato Pizza',
        'type': 'land_cooking',
        'skill_level': 'cooking_50',
        'min_qty': 40,
        'wait_seconds': 65 * 60,
        'energy_cost': 47,
        'buy_items': {
            'Slothmato Paste': 2,
            'Grainbow Flour': 2,
            'Cooking Mix': 1,
        }
    },
    "Cubecumber Loaf": {
        'type': 'land_cooking',
        'skill_level': 'cooking_55',
        'min_qty': 40,
        'wait_seconds': 65 * 60,
        'energy_cost': 47,
        'buy_items': {
            'Cubecumber Relish': 2,
            'Grainbow Flour': 2,
            'Cooking Mix': 1,
        }
    },
    'Popberry Jam': {
        'type': 'spec_cooking',
        'skill_level': 'cooking_0',
        'min_qty': 41,
        'wait_seconds': 15 * 60,
        'energy_cost': 11,
        'buy_items': {
            'Popberry': 2,
        }
    }
}


def prepare_make_item():
    stove_lv2 = image_tool.find_target('stove_level_2.png')
    name = None
    count = 0
    buy_items = {}

    chest_out = []
    for index in making_chest_items:
        chest_item = making_chest_items.get(index)
        if chest_item.get('name') == 'Tato Hash':
            chest_out.append(index)

    if len(chest_out) > 0:
        open_making_chest()  # 打开箱子
        time.sleep(1)
        cell_items = driver.find_elements(By.CLASS_NAME, 'InventoryWindow_inventoryItem__z7YhV')
        for index in chest_out:
            cell_elem = cell_items[index]
            if cell_elem:
                ac.move_to_element(cell_elem).perform()
                ac.context_click().perform()
                time.sleep(0.5)
                ac.context_click().perform()
                making_chest_items[index] = {}  # 更新箱子库存
        action.escape()
        action.escape()
        game.get_backpack()

    if name is None:
        # 第一轮检查做小数量
        for target_name in craft_only_items:
            name, count, buy_items = check_item(target_name, stove_lv2, 20)
            if name is None:
                continue
            else:
                break
        log.info(f'round_1_check: {name}')

    if name is None:
        # 第二轮检查做大数量
        for target_name in craft_only_items:
            item_config = craft_only_items.get(target_name, {})
            name, count, buy_items = check_item(target_name, stove_lv2, item_config.get('min_qty', 10))
            if name is None:
                continue
            else:
                break
        log.info(f'round_2_check: {name}')

    return name, count, buy_items


def check_item(target_name, stove_lv2, target_need_qty):
    item_config = craft_only_items.get(target_name, {})

    # 检查技能要求
    skill, min_level = (item_config.get('skill_level').split('_') + [None])[:2]
    skill_level = float(skills.get(skill, 0))
    if skill_level < float(min_level):
        return None, 0, {}

    target_type = item_config.get('type')
    if target_type == 'land_cooking':
        land_no, region = get_land_and_region()
        if land_no is None:
            return None, 0, {}
    if target_type == 'spec_cooking' or target_type == 'spec_cooking_v2':
        if cache.get(f'spec_cooking_{user_id}'):
            return None, 0, {}
    if target_type == 'metalworking':
        if cache.get(f'metalworking_{user_id}'):
            return None, 0, {}


    target_has_qty = game.get_backpack_qty(target_name) + get_making_chest_qty(target_name)
    if target_has_qty < target_need_qty:
        make_count = 0
        if target_type == 'metalworking':
            make_count = 1
        if target_type == 'spec_cooking':
            make_count = 9
        if target_type == 'land_cooking':
            make_count = 10
        if target_type == 'spec_cooking_v2':
            if stove_lv2 is None:
                return None, 0, {}
            make_count = 9
        # 检查依赖项
        make_items = item_config.get('make_items', {})
        for make_name in make_items:
            need_qty = make_count * make_items.get(make_name)
            has_qty = game.get_backpack_qty(make_name)
            if has_qty < need_qty:
                log.info(f'make {target_name} need {make_name}')
                return check_item(make_name, stove_lv2, need_qty)

        need_buy_items = {}
        item_buy_items = item_config.get('buy_items', {})
        for buy_name in item_buy_items:
            need_qty = item_buy_items.get(buy_name)
            has_qty = game.get_backpack_qty(buy_name)
            buy_qty = (need_qty * make_count) - has_qty
            if buy_qty > 0:
                need_buy_items[buy_name] = buy_qty
        if target_type == 'spec_cooking' or target_type == 'spec_cooking_v2':
            log_name = 'Whittlewood Log'
            if game.get_backpack_qty(log_name) < 50:
                need_buy_items[log_name] = 50
        return target_name, make_count, need_buy_items
    return None, 0, {}


def get_making_chest_qty(item_name):
    qty = 0
    for item in making_chest_items.values():
        if item.get('name') == item_name:
            qty += item.get('qty', 0)
    return qty


def make_item(name, make_count):
    target_config = craft_only_items.get(name)
    target_type = target_config.get('type')
    wait_seconds = target_config.get('wait_seconds', 60 * 60)

    # 检查能量
    energy_cost = make_count * target_config.get('energy_cost') + 10
    if game.get_energy() < energy_cost and game.is_total_wine_enough():
        tb_loc = image_tool.find_target('task_board.png')
        tb_x, tb_y = tb_loc
        game.drink_wine(max(500, energy_cost), tb_x + 166, tb_y + 66)
        action.goto_task_board()
    if game.get_energy() < energy_cost:
        return
    if target_type == 'metalworking':
        cache.set(f'metalworking_{user_id}', name, wait_seconds)
        metalworking(target_config.get('craft_name', name))
    elif target_type == 'spec_cooking' or target_type == 'spec_cooking_v2':
        cache.set(f'spec_cooking_{user_id}', name, wait_seconds)
        spec_cooking(target_config.get('craft_name', name))

    elif target_type == 'land_cooking':
        land_no, _ = get_land_and_region()
        log.debug(f'land_cooking: {land_no}_{region}')
        if land_no is not None:
            cache.set(f'land_cooking_{land_no}_{region}', name, wait_seconds)
            land_cooking(land_no, target_config.get('craft_name', name))
    else:
        log.info('unknown make type')

    return wait_seconds


def spec_cooking(item_name):
    action.goto_task_board()
    movement.keep_move_left(1.5)
    time.sleep(1)
    offset_xs = [-350, -200, -70]
    offset_ys = [-145, -20, 120]
    log_index, _ = game.get_backpack_index_and_qty('Whittlewood Log')

    tb_x, tb_y = image_tool.find_target('task_board.png')
    for x in offset_xs:
        for y in offset_ys:
            collect(tb_x + x, tb_y + y)
            cook(tb_x + x, tb_y + y, log_index, item_name)

    time.sleep(2)
    movement.keep_move_right(1.5)
    time.sleep(1)


def land_cooking(land_no, item_name):
    action.goto_land(land_no)
    movement.keep_move_up(1.6)
    movement.keep_move_left(random.randint(20, 30) / 10)
    action.move_to('land_house_door.png', delta_x=40)
    action.wait_page_loaded()
    movement.keep_move_up(2)
    movement.keep_move_left(2.5)

    for _ in range(2):
        done_stoves = image_tool.find_all_targets('stove_level_3_done.png')
        for stove_x, stove_y in done_stoves:
            stove_x = stove_x + 50
            stove_y = stove_y + 50
            collect(stove_x, stove_y)
    for _ in range(2):
        idle_stoves = image_tool.find_all_targets('stove_level_3_idle.png')
        for stove_x, stove_y in idle_stoves:
            stove_x = stove_x + 50
            stove_y = stove_y + 50
            cook(stove_x, stove_y, -1, item_name)


def get_land_and_region():
    land_no = config.get_env('land_cooking')
    if land_no is None:
        return None, None
    region = 1
    if cache.get(f'land_cooking_{land_no}_{region}'):
        return None, None
    return land_no, region


def collect(x, y):
    try:
        if action.hover_bubble_text_is(x, y, 'Ready to Collect'):
            action.click()
            time.sleep(0.5)
    except:
        pass


def cook(x, y, log_index, cooking_item_name):
    try:
        if log_index > 0 and action.hover_bubble_text_is(x, y, 'Add 1 Log'):
            game.use_backpack_item(log_index)
            time.sleep(0.5)
            action.click()
            action.escape()
            time.sleep(0.5)
        if action.hover_bubble_text_is(x, y, 'Click to Cook'):
            action.click()
            time.sleep(1)
            opt = action.find_element(By.XPATH, f"//span[text()='{cooking_item_name}']", cooking_item_name, 1)
            if opt is None:
                action.escape()
                time.sleep(1)
                action.click()
                opt = action.find_element(By.XPATH, f"//span[text()='{cooking_item_name}']", cooking_item_name, 1)
            opt.click()
            for _ in range(10):
                craft_button = action.find_element(By.CLASS_NAME, "Crafting_craftingButton__Qd6Ke", 'CraftButton', 1)
                if craft_button is None:
                    continue
                if craft_button.text == 'Collect':
                    if craft_button.is_enabled():
                        craft_button.click()
                        time.sleep(3)
                        continue
                if craft_button.text == 'Create':
                    if craft_button.is_enabled():
                        craft_button.click()
                        time.sleep(1)
                    action.escape()
                    action.escape()
                    break
                time.sleep(1)
            return 1
        return 0
    except Exception as e:
        print(e)
        return 0


def metalworking(item_name):
    ac = ActionChains(driver)
    movement.keep_move_right(1.8)
    # 检查是否有工作台
    station_image = 'metalworking.png'
    stations = image_tool.find_all_targets(station_image)
    kit_name = 'Basic Metalworking Kit'
    buy_items = {}
    if len(stations) == 0:
        has_qty = game.get_backpack_qty(kit_name)
        if has_qty < 1:
            buy_items[kit_name] = 1
    if len(buy_items) > 0:
        trade_helper.goto_buy_position()
        filter_input = trade_helper.open_market_buy()
        for buy_name in buy_items:
            buy_qty = buy_items.get(buy_name)
            trade_helper.market_buy_item(filter_input, buy_name, buy_qty)
        action.escape()
        action.escape()
        action.goto_task_board()
        movement.keep_move_right(1.8)
        game.get_backpack()
    if len(stations) == 0:
        right_door_image = 'house_manager_root.png'
        (door_x, door_y) = image_tool.find_target(right_door_image)
        kit_index, _ = game.get_backpack_index_and_qty(kit_name)
        game.use_backpack_item(kit_index)
        ac.reset_actions()
        ac.move_by_offset(door_x + 177, door_y + 110).click().perform()
        time.sleep(1)
        action.escape()
        stations = image_tool.find_all_targets(station_image)

    for (x, y) in stations:
        action.click_by_offset(x, y)
        opt = action.find_element(By.XPATH, f"//span[text()='{item_name}']", item_name, 3)
        if opt is None:
            action.escape()
            time.sleep(1)
            action.click()
            opt = action.find_element(By.XPATH, f"//span[text()='{item_name}']", item_name, 10)
        opt.click()
        time.sleep(1)
        for _ in range(10):
            craft_button = action.find_element(By.CLASS_NAME, "Crafting_craftingButton__Qd6Ke", 'CraftButton', 2)
            if craft_button.text == 'Collect':
                if craft_button.is_enabled():
                    craft_button.click()
                    time.sleep(3)
                    continue
            if craft_button.text == 'Create':
                if craft_button.is_enabled():
                    craft_button.click()
                    time.sleep(1)
                action.escape()
                action.escape()
                break
            time.sleep(1)
    movement.keep_move_left(1.8)

def open_making_chest():
    hmr_image = 'house_manager_root.png'
    # 取物品
    hmr_loc = image_tool.find_target(hmr_image)
    hmr_x, hmr_y = hmr_loc
    action.click_by_offset(hmr_x + 40, hmr_y + 100)


if __name__ == "__main__":
    parser = TaskHelper.default_args_parser('Craft')
    args = parser.parse_args()
    task_helper = TaskHelper.from_args(args)

    user_id = args.user_id
    log = Log(user_id)
    cache = Cache()

    can_craft = False
    land_no = config.get_env('land_cooking')
    if land_no is None:
        print('land_cooking not configured')
    region = user_id % 3 + 1
    if land_no:
        if cache.get(f'land_cooking_{land_no}_{region}'):
            print(f'land_cooking region[{region}] is using')
        else:
            can_craft = True
    if cache.get(f'spec_cooking_{user_id}'):
        print('spec_cooking is using')
    else:
        can_craft = True
    if cache.get(f'metalworking_{user_id}'):
        print('metalworking is using')
    else:
        can_craft = True
    if not can_craft:
        sys.exit()

    try:

        # 启动窗口
        driver = AdsWindow(user_id).open(False)
        ac = ActionChains(driver)
        action = WebDriverAction(driver, user_id=user_id)
        movement = Movement(driver)
        image_tool = ImageTool(driver)
        game = Game(driver, user_id)
        trade_helper = TradeHelper(driver, user_id)
        account = config.get_account(user_id)
        log.info(f"craft start")

        # 进入游戏
        game.enter_game(user_id)

        snapshot = game.snapshot(user_id, 'after_collect_mail')
        skills = snapshot.get('skills')

        action.goto_task_board()

        open_making_chest()
        making_chest_items = game.chest_scan()
        action.escape()

        max_wait = None
        for _ in range(4):
            make_name, make_count, extra_buy_items = prepare_make_item()
            if make_name is None:
                break
            if len(extra_buy_items) > 0:
                trade_helper.goto_buy_position()
                trade_helper.buy()
                action.escape()
                # 额外买工作需要的材料
                filter_input = trade_helper.open_market_buy()
                for buy_name in extra_buy_items:
                    buy_qty = extra_buy_items.get(buy_name)
                    buy_result = trade_helper.market_buy_item(filter_input, buy_name, buy_qty)
                action.escape()

            log.debug(f'make {make_name}')
            wait_seconds = make_item(make_name, make_count)
            if max_wait is None or wait_seconds > max_wait:
                max_wait = wait_seconds

        if max_wait:
            task_helper.add_task('craft.py', delay_seconds=max_wait, ignore_running=True)

        task_helper.task_success()
        game.snapshot(user_id, 'after craft', include_skills=False)
    except:
        task_helper.task_fail()
        task_helper.add_task('craft.py', delay_seconds=0, ignore_running=True, retry=True)